﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RonaldCamcam.XBeeFramework.Api
{
    public class ResponseFactory
    {        
        public static string DecodeStatus(byte byteStatus)
        {
            switch (byteStatus)
            {
                case 0: return Response.OK;
                case 1: return Response.ERROR;
                case 2: return Response.INVALID_COMMAND;
                case 3: return Response.INVALID_PARAMETER;
                default: return Response.INVALID_RESPONSE; 
            }
        }

        public static bool VerifyCheckSum(byte[] receivedByte)
        {
            //Validate CheckSum First
            int sum = 0;
            for (int ctr = 3; ctr < receivedByte.Length; ctr++)
            {
                sum += receivedByte[ctr];
            }
            sum &= 255;

            return (sum.ToString("X") == "FF") ? true : false;                
        }

        public static Response Parse(List<byte> receivedByte, Encoding enc)
        {
            if (receivedByte.Count == 0)
            {
                return new Response();
            }
            else
            {
                Response response = new Response();
                response.HexPayload = receivedByte.ToHexString();                

                if (VerifyCheckSum(receivedByte.ToArray()))
                {
                    //valid response, now parse payload
                    response.Status = DecodeStatus(receivedByte[7]);

                    if (response.Status == Response.OK)
                    {
                        //then process payload                        
                        Queue<byte> data = new Queue<byte>();

                        foreach (byte b in receivedByte)
                        {                            
                            data.Enqueue(b);
                        }                        

                        int byteCounter = 0;
                        int checkSumPointer = data.Count;

                        while (data.Count != 0)
                        {
                            //skip ACK, since we already read it above
                            if (byteCounter == 7)
                            {
                                data.Dequeue();
                                byteCounter++;
                                continue;
                            }

                            if (byteCounter == 0) //this is the delimiter address
                                data.Dequeue();

                            if (byteCounter == 1)
                                data.Dequeue(); //MSB

                            if (byteCounter == 2)
                                data.Dequeue(); //LSB

                            if (byteCounter == 3)
                                data.Dequeue(); //API Identifier

                            if (byteCounter == 4)
                                data.Dequeue(); //Frame Id/Ack

                            if (byteCounter == 5)
                                response.ATCommand = data.Dequeue().ToHexString(); //AT Command

                            if (byteCounter == 6)
                                response.ATCommand += data.Dequeue().ToHexString(); //AT Command

                            if (byteCounter > 7 && byteCounter < checkSumPointer - 1)
                            {
                                //response value                                    
                                response.Value.Add(data.Dequeue());
                            }

                            if (byteCounter == checkSumPointer - 1)
                                response.CheckSum = enc.GetString(new byte[] { data.Dequeue() });

                            byteCounter++;
                        }
                    }                                        
                }
                else
                {
                    response.Status = Response.INVALID_CHECKSUM;
                }

                return response;
            }
        }

        internal static bool VerifyRemoteCheckSum(byte[] receivedByte)
        {
            int sum = 0;
            for (int ctr = 3; ctr < receivedByte.Length; ctr++)
            {
                sum += receivedByte[ctr];
            }
            sum &= 255;

            return (sum.ToString("X") == "FF") ? true : false;                   
        }

        internal static Response ParseRemoteData(List<byte> receivedByte, Encoding enc)
        {
            if (receivedByte.Count == 0)
            {
                return new Response();
            }
            else
            {
                Response response = new Response();
                response.HexPayload = receivedByte.ToHexString();

                if (VerifyRemoteCheckSum(receivedByte.ToArray()))
                {
                    //valid response, now parse payload
                    response.Status = DecodeStatus(receivedByte[17]);

                    if (response.Status == Response.OK)
                    {
                        //then process payload                        
                        Queue<byte> data = new Queue<byte>();

                        foreach (byte b in receivedByte)
                        {
                            data.Enqueue(b);
                        }

                        int byteCounter = 0;
                        int checkSumPointer = data.Count;

                        while (data.Count != 0)
                        {
                            //skip ACK, since we already read it above
                            if (byteCounter == 7)
                            {
                                data.Dequeue();
                                byteCounter++;
                                continue;
                            }

                            if (byteCounter == 0) //this is the delimiter address
                                data.Dequeue();

                            if (byteCounter == 1)
                                data.Dequeue(); //MSB

                            if (byteCounter == 2)
                                data.Dequeue(); //LSB

                            if (byteCounter == 3)
                                data.Dequeue(); //API Identifier

                            if (byteCounter == 4)
                                data.Dequeue(); //Frame Id/Ack

                            if (byteCounter == 15)
                                response.ATCommand = data.Dequeue().ToHexString(); //AT Command

                            if (byteCounter == 16)
                                response.ATCommand += data.Dequeue().ToHexString(); //AT Command

                            if (byteCounter > 17 && byteCounter < checkSumPointer - 1)
                            {
                                //response value                                    
                                response.Value.Add(data.Dequeue());
                            }

                            if (byteCounter == checkSumPointer - 1)
                                response.CheckSum = enc.GetString(new byte[] { data.Dequeue() });

                            byteCounter++;
                        }
                    }
                }
                else
                {
                    response.Status = Response.INVALID_CHECKSUM;
                }

                return response;
            }
        }
    }
}
